package com.upb.webserver.order;

import cn.hutool.core.collection.CollectionUtil;
import com.upb.webserver.chain.ChainService;
import com.upb.webserver.common.constant.Constant;
import com.upb.webserver.common.enums.*;
import com.upb.webserver.common.exception.WebServerException;
import com.upb.webserver.common.pojo.order.ReqAddWorkOrderOfNewApplicationVO;
import com.upb.webserver.common.pojo.order.ReqAddWorkOrderOfNewChainVO;
import com.upb.webserver.common.returncode.ConstantCode;
import com.upb.webserver.common.tools.JsonUtils;
import com.upb.webserver.common.tools.MybatisExampleTools;
import com.upb.webserver.dao.entity.TbWorkOrder;
import com.upb.webserver.dao.entity.TbWorkOrderExample;
import com.upb.webserver.dao.mapper.TbWorkOrderMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Slf4j
@Service
public class WorkOrderManager {

    @Autowired
    private TbWorkOrderMapper workOrderMapper;
    @Autowired
    private ChainService chainService;

    /**
     * @param orderTypeEnumList
     * @return
     */
    public List<TbWorkOrder> listWorkOrderWhichHadNotBeanHandleSuccess(List<OrderTypeEnum> orderTypeEnumList) {
        log.info("start exec method [listWorkOrderWhichHadNotBeanHandleSuccess]. orderTypeEnumList:{}", JsonUtils.objToString(orderTypeEnumList));

        List<Byte> orderStatusList = Arrays.asList(OrderStatusEnum.APPLYING_BY_DEVELOPER.getValue(), OrderStatusEnum.WAIT_FOR_MANAGER_HANDLE.getValue(), OrderStatusEnum.REJECTED_BY_MANAGER.getValue(), OrderStatusEnum.HANDLE_FAIL_BY_MANAGER.getValue(), OrderStatusEnum.HANDLING_BY_MANAGER.getValue());
        Map<String, Object> inParam = new HashMap<>();
        inParam.put("status", orderStatusList);

        List<List<TbWorkOrder>> queryResultList = new ArrayList<>(orderTypeEnumList.size());
        for (OrderTypeEnum orderTypeEnum : orderTypeEnumList) {
            TbWorkOrderExample example = MybatisExampleTools.initSampleExample(TbWorkOrderExample.class, new TbWorkOrder(orderTypeEnum.getValue(), null, null), inParam);
            example.setOrderByClause(Constant.ORDER_BY_GMT_MODIFIED_DESC);
            List<TbWorkOrder> workOrderList = workOrderMapper.selectByExampleWithBLOBs(example);
            queryResultList.add(workOrderList);
        }

        List<TbWorkOrder> allList = new ArrayList<>();
        queryResultList.stream().forEach(allList::addAll);
//        List<TbWorkOrder> rspList = allList.stream().filter(o -> StringUtils.isBlank(o.getTargetTable()) || Objects.isNull(o.getTargetId())).collect(Collectors.toList());
        log.info("success exec method [listWorkOrderWhichHadNotBeanHandleSuccess]. result:{}", JsonUtils.objToString(allList));

        return allList;
    }


    /**
     * @param tableNameEnum
     * @param targetId
     * @param orderStatusEnum
     */
    public void updateStatusByTargetTableAndId(TableNameEnum tableNameEnum, Integer targetId, OrderStatusEnum orderStatusEnum, String description) {
        log.info("start exec method [updateStatusByTargetTableAndId]. tableName:{} targetId:{} orderStatusEnum:{} description:{}", tableNameEnum.getName(), targetId, orderStatusEnum.getValue(), description);

        //param
        TbWorkOrder param = new TbWorkOrder();
        param.setTargetTable(tableNameEnum.getName());
        param.setTargetId(targetId);
        TbWorkOrderExample example = MybatisExampleTools.initSampleExample(TbWorkOrderExample.class, param);

        //query
        TbWorkOrder workOrder = workOrderMapper.getOneByExample(example).orElse(null);
        if (Objects.isNull(workOrder)) {
            log.warn("not success exec method [updateStatusByTargetTableAndId].  not found record by tableName:{} targetId:{} ", tableNameEnum.getName(), targetId);
            return;
        }

        workOrder.setStatus(orderStatusEnum.getValue());
        workOrder.setDescription(description);
        workOrder.setGmtModified(new Date());
        workOrderMapper.updateByPrimaryKeyWithBLOBs(workOrder);
        log.info("success exec method [updateStatusByTargetTableAndId]. tableName:{} targetId:{} orderStatusEnum:{}", tableNameEnum.getName(), targetId, orderStatusEnum.getValue());
    }


    /**
     * @return
     */
    public List<TbWorkOrder> getAllWorkOrderOfNewChain() {
        log.info("start exec method [getAllWorkOrderOfNewChain].");
        //param
        TbWorkOrderExample example = new TbWorkOrderExample();
        TbWorkOrderExample.Criteria criteria = example.createCriteria();
        criteria.andTypeIn(Constant.ORDER_TYPE_LIST_NEW_CHAIN);

        //query workOrder
        List<TbWorkOrder> workOrderList = workOrderMapper.selectByExampleWithBLOBs(example);
        log.info("success exec method [getAllWorkOrderOfNewChain].");
        return workOrderList;
    }


    /**
     * @return
     */
    public List<TbWorkOrder> getAllWorkOrderOfNewApplication() {
        log.info("start exec method [getAllWorkOrderOfNewApplication].");
        //param
        TbWorkOrderExample example = new TbWorkOrderExample();
        TbWorkOrderExample.Criteria criteria = example.createCriteria();
        criteria.andTypeIn(Constant.ORDER_TYPE_LIST_NEW_APP);

        //query workOrder
        List<TbWorkOrder> workOrderList = workOrderMapper.selectByExampleWithBLOBs(example);
        log.info("success exec method [getAllWorkOrderOfNewApplication].");
        return workOrderList;
    }

    /**
     * @return
     */
    public Set<Integer> getAllHostIdFromWorkOrderOfNewChain() {
        log.info("start exec method [getAllHostIdFromWorkOrderOfNewChain].");

        //query workOrder
        List<TbWorkOrder> workOrderList = getAllWorkOrderOfNewChain();
        if (CollectionUtil.isEmpty(workOrderList)) {
            log.info("finish exec method [getAllHostIdFromWorkOrderOfNewChain]. not found workOrder of new chain");
            return CollectionUtil.newHashSet();
        }

        Set<Integer> hostIdSet = new HashSet<>();
        for (TbWorkOrder workOrder : workOrderList) {
            ReqAddWorkOrderOfNewChainVO chainDetailVO = JsonUtils.stringToObj(workOrder.getDetail(), ReqAddWorkOrderOfNewChainVO.class);
            Set<Integer> hostIdSetTemp = this.getAllHostIdFromWorkOrderDetail(chainDetailVO);
            hostIdSet.addAll(hostIdSetTemp);
        }

        log.info("success exec method [getAllHostIdFromWorkOrderOfNewChain]. result:{}", JsonUtils.objToString(hostIdSet));
        return hostIdSet;
    }

    /**
     * @param chainDetailVO
     * @return
     */
    public Set<Integer> getAllHostIdFromWorkOrderDetail(ReqAddWorkOrderOfNewChainVO chainDetailVO) {
        log.info("start exec method [getAllHostIdFromWorkOrderOfNewChain]. chainDetailVO:{}", JsonUtils.objToString(chainDetailVO));

        // hostIdSet
        Set<Integer> hostIdSet = new HashSet<>();
        if (ChainTypeEnum.FISCO.getId() == chainDetailVO.getChainType()) {
            chainDetailVO.getFiscoOrgList()
                    .stream()
                    .forEach(org -> {
                        Optional.ofNullable(org.getFiscoHostList()).ifPresent(hostList -> hostList.stream().forEach(host -> hostIdSet.add(host.getFiscoHostId())));
                    });
        }

        log.info("success exec method [getAllHostIdFromWorkOrderOfNewChain]. result:{}", JsonUtils.objToString(hostIdSet));
        return hostIdSet;
    }


    /**
     * @param workOrderId
     * @return
     */
    public TbWorkOrder verifyWorkOrderId(int workOrderId) {
        log.info("start exec method [verifyWorkOrderId]. workOrderId:{}", workOrderId);
        TbWorkOrderExample example = new TbWorkOrderExample();
        TbWorkOrderExample.Criteria criteria = example.createCriteria();
        criteria.andIdEqualTo(workOrderId);

        List<TbWorkOrder> workOrderList = workOrderMapper.selectByExampleWithBLOBs(example);
        if (CollectionUtil.isEmpty(workOrderList)) {
            log.warn("fail exec method [verifyWorkOrderId]. not found record by workOrderId：{}", workOrderId);
            throw new WebServerException(ConstantCode.INVALID_WORK_ORDER_ID);
        }
        log.info("success exec method [verifyWorkOrderId]. result:{}", JsonUtils.objToString(workOrderList.get(0)));
        return workOrderList.get(0);
    }


    /**
     * @param hostIdSet
     * @return
     */
    public Set<Integer> getNewChainWorkOrderSetByHostSet(Set<Integer> hostIdSet) {
        log.info("start exec method [getNewChainWorkOrderSetByHostSet]. hostIdSet:{}", hostIdSet);
        //query workOrder list of new chain
        TbWorkOrderExample example = new TbWorkOrderExample();
        TbWorkOrderExample.Criteria criteria = example.createCriteria();
        criteria.andTypeIn(Constant.ORDER_TYPE_LIST_NEW_CHAIN);
        List<TbWorkOrder> workOrderList = workOrderMapper.selectByExampleWithBLOBs(example);

        //workOrderIdSet
        Set<Integer> workOrderIdSet = new HashSet<>();

        //cancel this limit
        if (1 == 1) {
            return workOrderIdSet;
        }

        for (TbWorkOrder tbWorkOrder : workOrderList) {
            ReqAddWorkOrderOfNewChainVO chainDetail = JsonUtils.objToJavaBean(tbWorkOrder.getDetail(), ReqAddWorkOrderOfNewChainVO.class);
            if (ChainTypeEnum.FISCO.getId() == chainDetail.getChainType()) {
                chainDetail.getFiscoOrgList()
                        .stream()
                        .filter(fOrg -> CollectionUtil.isNotEmpty(fOrg.getFiscoHostList()))
                        .forEach(org -> {
                            org.getFiscoHostList().stream()
                                    .filter(host -> hostIdSet.contains(host.getFiscoHostId()))
                                    .findFirst()
                                    .ifPresent(hostFinal -> workOrderIdSet.add(tbWorkOrder.getId()));
                        });
            }
        }
        log.info("success exec method [getNewChainWorkOrderSetByHostSet]. hostIdSet:{} result:{}", JsonUtils.objToString(hostIdSet), JsonUtils.objToString(workOrderIdSet));
        return workOrderIdSet;
    }

    /**
     * @param companyIdList
     * @return
     */
    public Set<Integer> getAllWorkOrderOfNewChainByCompanyIdList(List<Integer> companyIdList) {
        log.info("start exec method [getAllWorkOrderOfNewChainByCompanyId]. companyIdList:{}", JsonUtils.objToString(companyIdList));

        if (CollectionUtil.isEmpty(companyIdList))
            return Collections.EMPTY_SET;

        int pageNumber = 0;
        Set<Integer> orderIdSet = new HashSet<>();
        while (true) {
            //next page
            pageNumber++;

            //param
            TbWorkOrderExample example = MybatisExampleTools.initSamplePageExample(TbWorkOrderExample.class, pageNumber, 50, null); //TODO
            TbWorkOrderExample.Criteria criteria = example.createCriteria();
            criteria.andTypeIn(Constant.ORDER_TYPE_LIST_NEW_CHAIN);

            //query workOrderChain list
            List<TbWorkOrder> workOrderList = workOrderMapper.selectByExampleWithBLOBs(example);
            if (CollectionUtil.isEmpty(workOrderList)) {
                log.info("not found workOrder by pageNumber:{} pageSize:50 orderType:{}", pageNumber, JsonUtils.objToString(Constant.ORDER_TYPE_LIST_NEW_CHAIN));
                break;
            }

            for (TbWorkOrder tbWorkOrder : workOrderList) {
                ReqAddWorkOrderOfNewChainVO chainDetail = JsonUtils.objToJavaBean(tbWorkOrder.getDetail(), ReqAddWorkOrderOfNewChainVO.class);
                long recordCount = 0;
                if (ChainTypeEnum.FISCO.getId() == chainDetail.getChainType()) {
                    recordCount = chainDetail.getFiscoOrgList()
                            .stream()
                            .filter(fOrg -> companyIdList.contains(fOrg.getCompanyId()))
                            .count();
                }
                log.info("workOrderId:{} companyIdList:{} recordCount:{}", tbWorkOrder.getId(), JsonUtils.objToString(companyIdList), recordCount);
                if (recordCount > 0) {
                    orderIdSet.add(tbWorkOrder.getId());
                }
            }
        }
        log.info("success exec method [getAllWorkOrderOfNewChainByCompanyId]. companyIdList:{} result:{}", JsonUtils.objToString(companyIdList), JsonUtils.objToString(orderIdSet));
        return orderIdSet;
    }


    /**
     * @param companyIdList
     * @return
     */
    public Set<Integer> getAllWorkOrderOfNewApplicationByCompanyIdList(List<Integer> companyIdList) {
        log.info("start exec method [getAllWorkOrderOfNewApplicationByCompanyId]. companyId:{}", JsonUtils.objToString(companyIdList));

        if (CollectionUtil.isEmpty(companyIdList))
            return Collections.EMPTY_SET;

        int pageNumber = 0;
        Set<Integer> orderIdSet = new HashSet<>();
        while (true) {
            //next page
            pageNumber++;

            //param
            TbWorkOrderExample example = MybatisExampleTools.initSamplePageExample(TbWorkOrderExample.class, pageNumber, 50, null);
            TbWorkOrderExample.Criteria criteria = example.createCriteria();
            criteria.andTypeIn(Constant.ORDER_TYPE_LIST_NEW_APP);

            //query workOrderChain list
            List<TbWorkOrder> workOrderList = workOrderMapper.selectByExampleWithBLOBs(example);
            if (CollectionUtil.isEmpty(workOrderList)) {
                log.info("not found workOrder by pageNumber:{} pageSize:50 orderType:{}", pageNumber, JsonUtils.objToString(Constant.ORDER_TYPE_LIST_NEW_APP));
                break;
            }

            for (TbWorkOrder tbWorkOrder : workOrderList) {
                ReqAddWorkOrderOfNewApplicationVO appDetailVO = JsonUtils.objToJavaBean(tbWorkOrder.getDetail(), ReqAddWorkOrderOfNewApplicationVO.class);
                long recordCount = appDetailVO.getConfirmOrgList().stream().filter(org -> companyIdList.contains(org.getCompanyId())).count();
                log.info("workOrderId:{} companyIdList:{} recordCount:{}", tbWorkOrder.getId(), JsonUtils.objToString(companyIdList), recordCount);
                if (recordCount > 0) {
                    orderIdSet.add(tbWorkOrder.getId());
                }
            }
        }
        log.info("success exec method [getAllWorkOrderOfNewApplicationByCompanyId]. companyIdList:{} result:{}", JsonUtils.objToString(companyIdList), JsonUtils.objToString(orderIdSet));
        return orderIdSet;
    }


    /**
     * @param developerId
     * @return
     */
    public Set<Integer> getAllWorkOrderOfNewApplicationByDeveloperId(int developerId) {
        log.info("start exec method [getAllWorkOrderOfNewApplicationByDeveloperId]. developerId:{}", developerId);

        int pageNumber = 0;
        Set<Integer> orderIdSet = new HashSet<>();
        while (true) {
            //next page
            pageNumber++;

            //param
            TbWorkOrderExample example = MybatisExampleTools.initSamplePageExample(TbWorkOrderExample.class, pageNumber, 50, null);
            TbWorkOrderExample.Criteria criteria = example.createCriteria();
            criteria.andTypeIn(Constant.ORDER_TYPE_LIST_NEW_APP);

            //query workOrderChain list
            List<TbWorkOrder> workOrderList = workOrderMapper.selectByExampleWithBLOBs(example);
            if (CollectionUtil.isEmpty(workOrderList)) {
                log.info("not found workOrder by pageNumber:{} pageSize:50 orderType:{}", pageNumber, JsonUtils.objToString(Constant.ORDER_TYPE_LIST_NEW_APP));
                break;
            }

            for (TbWorkOrder tbWorkOrder : workOrderList) {
                ReqAddWorkOrderOfNewApplicationVO appDetailVO = JsonUtils.objToJavaBean(tbWorkOrder.getDetail(), ReqAddWorkOrderOfNewApplicationVO.class);
                long recordCount = appDetailVO.getConfirmOrgList()
                        .stream()
                        .filter(org -> org.getConfirmDeveloperId() != null && developerId == org.getConfirmDeveloperId())
                        .count();
                log.info("workOrderId:{} developerId:{} recordCount:{}", tbWorkOrder.getId(), developerId, recordCount);
                if (recordCount > 0) {
                    orderIdSet.add(tbWorkOrder.getId());
                }
            }
        }
        log.info("success exec method [getAllWorkOrderOfNewApplicationByDeveloperId]. developerId:{} result:{}", developerId, JsonUtils.objToString(orderIdSet));
        return orderIdSet;
    }


    /**
     * @param chainId
     * @return
     */
    public Set<Integer> getAllWorkOrderOfNewApplicationByChainId(int chainId) {
        log.info("start exec method [getAllWorkOrderOfNewApplicationByChainId]. chainId:{}", chainId);

        int pageNumber = 0;
        Set<Integer> orderIdSet = new HashSet<>();
        while (true) {
            //next page
            pageNumber++;

            //param
            TbWorkOrderExample example = MybatisExampleTools.initSamplePageExample(TbWorkOrderExample.class, pageNumber, 50, null);
            TbWorkOrderExample.Criteria criteria = example.createCriteria();
            criteria.andTypeIn(Constant.ORDER_TYPE_LIST_NEW_APP);

            //query workOrderChain list
            List<TbWorkOrder> workOrderList = workOrderMapper.selectByExampleWithBLOBs(example);
            if (CollectionUtil.isEmpty(workOrderList)) {
                log.info("not found workOrder by pageNumber:{} pageSize:50 orderType:{}", pageNumber, JsonUtils.objToString(Constant.ORDER_TYPE_LIST_NEW_APP));
                break;
            }

            for (TbWorkOrder tbWorkOrder : workOrderList) {
                ReqAddWorkOrderOfNewApplicationVO appDetailVO = JsonUtils.objToJavaBean(tbWorkOrder.getDetail(), ReqAddWorkOrderOfNewApplicationVO.class);
                log.info("workOrderId:{} chainId:{} inputChainId:{}", tbWorkOrder.getId(), appDetailVO.getChainId(), chainId);
                if (appDetailVO.getChainId() == chainId) {
                    orderIdSet.add(tbWorkOrder.getId());
                }
            }
        }
        log.info("success exec method [getAllWorkOrderOfNewApplicationByCompanyId]. chainId:{} result:{}", chainId, JsonUtils.objToString(orderIdSet));
        return orderIdSet;
    }


    /**
     * @param idSet
     * @return
     */
    public List<TbWorkOrder> getAllWorkOrderByIdSet(Set<Integer> idSet) {
        log.info("start exec method [getAllWorkOrderByIdSet]. idSet:{}", JsonUtils.objToString(idSet));
        if (CollectionUtil.isEmpty(idSet)) {
            log.info("finish exec method[getAllWorkOrderByIdSet], idSet is empty");
            return new ArrayList<>();
        }

        //example
        TbWorkOrderExample example = new TbWorkOrderExample();
        TbWorkOrderExample.Criteria criteria = example.createCriteria();
        criteria.andIdIn(CollectionUtil.newArrayList(idSet));

        // query chain list
        List<TbWorkOrder> workOrderList = workOrderMapper.selectByExampleWithBLOBs(example);
        log.info("success exec method [getAllWorkOrderByIdSet]. idSet:{} result:{}", JsonUtils.objToString(idSet), JsonUtils.objToString(workOrderList));
        return workOrderList;
    }


    /**
     * @param platform
     * @param creatorAccountId
     * @return
     */
    public long countWorkOrderByCreator(PlatformEnum platform, int creatorAccountId) {
        log.debug("start exec method [countWorkOrderByCreator]. platform:{} creatorAccountId:{}", platform, creatorAccountId);
        TbWorkOrderExample example = MybatisExampleTools.initSampleExample(TbWorkOrderExample.class, new TbWorkOrder(platform, creatorAccountId));
        long count = workOrderMapper.countByExample(example);
        log.debug("success exec method [countWorkOrderByCreator]. platform:{} creatorAccountId:{} count:{}", platform, creatorAccountId, count);
        return count;
    }
}
